﻿using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

namespace Ls.ImageSharep.App
{

    public delegate void CallTemplateBack();
    #region  数据项目
    public class ListDataItemModel
    {
        public int X { get; set; }
        public int Y { get; set; }

        public string Content { get; set; }

        public string DisplayText { get; set; }

        public int Id { get; set; }

        public int WrappingLength { get; set; }

        public float FontSize { get; set; }
    }
    #endregion
    public class LsApp
    {
        private static List<ListDataItemModel> _listitems;

        public static List<ListDataItemModel> ListItems
        {
            get
            {
                if (_listitems == null)
                {
                    _listitems = new List<ListDataItemModel>();
                }
                return _listitems;
            }
            set { _listitems = value; }
        }

        public static void WriteLog(string documentName, string msg)
        {
            string errorLogFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");
            if (!System.IO.Directory.Exists(errorLogFilePath))
            {
                System.IO.Directory.CreateDirectory(errorLogFilePath);
            }
            string logFile = System.IO.Path.Combine(errorLogFilePath, documentName + "@" + DateTime.Today.ToString("yyyy-MM-dd") + ".txt");
            bool writeBaseInfo = System.IO.File.Exists(logFile);
            StreamWriter swLogFile = new StreamWriter(logFile, true, Encoding.Unicode);
            swLogFile.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "\t" + msg);
            swLogFile.Close();
            swLogFile.Dispose();
        }
        public static string ObjectToString( List<ListDataItemModel> objlist)
        {
            StringBuilder sb = new StringBuilder();
            if (objlist != null && objlist.Count>0)
            {
                foreach (var item in objlist)
                {
                    var p = item.GetType().GetProperties();
                    StringBuilder sbp = new StringBuilder();
                    foreach (var pinfo in p)
                    {
                        sbp.Append($"{pinfo.Name}:{pinfo.GetValue(item)} ");
                    }
                    sb.AppendLine(sbp.ToString());
                }
            }
            return sb.ToString();
        }
        public static byte[] ImgToByt(System.Drawing.Image img)
        {
            //MemoryStream ms = new MemoryStream();
            //byte[] imagedata = null;
            //img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            //imagedata = ms.GetBuffer();
            //return imagedata;

            ImageConverter imgconv = new ImageConverter();
            byte[] b = (byte[])imgconv.ConvertTo(img, typeof(byte[]));
            return b;
        }


        public static Stream GetImagebase64(string imageCode)
        {
            byte[] bytes = Convert.FromBase64String(imageCode);
            MemoryStream s = new MemoryStream(bytes, true);
            s.Write(bytes, 0, bytes.Length);
            return s;
        }

        public static MemoryStream ImgToMemoryStream(SixLabors.ImageSharp.Image image)
        {
            MemoryStream memoryStream = new MemoryStream();
            image.Save(memoryStream, new JpegEncoder());
            return memoryStream;
        }

        public static SixLabors.Fonts.Font GetFont(float size)
        {
            SixLabors.Fonts.FontCollection fonts = new SixLabors.Fonts.FontCollection();
            var fontFamily = fonts.Add(AppDomain.CurrentDomain.BaseDirectory + @"/font/SIMHEI.TTF"); //字体的路径（电脑自带字体库，去copy出来）
            var font = fontFamily.CreateFont(size, SixLabors.Fonts.FontStyle.Bold);
            return font;

        }


        public static SixLabors.Fonts.TextOptions GetTextOptions(float fontSize, float wrappingLength)
        {
            SixLabors.Fonts.TextOptions textOptions = new(GetFont(20))
            {
                WrappingLength = wrappingLength,
                WordBreaking = SixLabors.Fonts.WordBreaking.BreakAll
            };
            return textOptions;
        }

        public static SixLabors.Fonts.TextOptions GetTextOptions(float fontSize, float wrappingLength, float x, float y)
        {
            SixLabors.Fonts.TextOptions textOptions = new(GetFont(fontSize))
            {
                WrappingLength = wrappingLength,
                //WordBreaking = SixLabors.Fonts.WordBreaking.BreakAll,
                Origin = new System.Numerics.Vector2(x, y)
            };
            return textOptions;
        }


        
    }

    public static class LsAppExtens
    {
        // Implements a full image mutating pipeline operating on IImageProcessingContext
        public static IImageProcessingContext ConvertToAvatar(this IImageProcessingContext processingContext, SixLabors.ImageSharp.Size size, float cornerRadius)
        {
            return processingContext.Resize(new ResizeOptions
            {
                Size = size,
                Mode = ResizeMode.Crop
            }).ApplyRoundedCorners(cornerRadius);
        }

        // This method can be seen as an inline implementation of an `IImageProcessor`:
        // (The combination of `IImageOperations.Apply()` + this could be replaced with an `IImageProcessor`)
        public static IImageProcessingContext ApplyRoundedCorners(this IImageProcessingContext ctx, float cornerRadius)
        {
            SixLabors.ImageSharp.Size size = ctx.GetCurrentSize();
            IPathCollection corners = BuildCorners(size.Width, size.Height, cornerRadius);

            ctx.SetGraphicsOptions(new GraphicsOptions()
            {
                Antialias = true,
                AlphaCompositionMode = PixelAlphaCompositionMode.DestOut // enforces that any part of this shape that has color is punched out of the background
            });

            // mutating in here as we already have a cloned original
            // use any color (not Transparent), so the corners will be clipped
            foreach (var c in corners)
            {
                ctx = ctx.Fill(SixLabors.ImageSharp.Color.Red, c);
            }
            return ctx;
        }


        public static IImageProcessingContext ApplyScalingWaterMark(this IImageProcessingContext processingContext,
          SixLabors.Fonts.Font font,
         string text,
         SixLabors.ImageSharp.Color color,
         float padding,
         bool wordwrap)
        {
            if (wordwrap)
            {
                return processingContext.ApplyScalingWaterMarkWordWrap(font, text, color, padding);
            }
            else
            {
                return processingContext.ApplyScalingWaterMarkSimple(font, text, color, padding);
            }
        }

        public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius)
        {
            // first create a square
            var rect = new RectangularPolygon(-0.5f, -0.5f, cornerRadius, cornerRadius);

            // then cut out of the square a circle so we are left with a corner
            IPath cornerTopLeft = rect.Clip(new EllipsePolygon(cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius));

            // corner is now a corner shape positions top left
            //lets make 3 more positioned correctly, we can do that by translating the original around the center of the image

            float rightPos = imageWidth - cornerTopLeft.Bounds.Width + 1;
            float bottomPos = imageHeight - cornerTopLeft.Bounds.Height + 1;

            // move it across the width of the image - the width of the shape
            IPath cornerTopRight = cornerTopLeft.RotateDegree(90).Translate(rightPos, 0);
            IPath cornerBottomLeft = cornerTopLeft.RotateDegree(-90).Translate(0, bottomPos);
            IPath cornerBottomRight = cornerTopLeft.RotateDegree(180).Translate(rightPos, bottomPos);

            return new PathCollection(cornerTopLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
        }

        public static IImageProcessingContext ApplyScalingWaterMarkSimple(
        this IImageProcessingContext processingContext,
        SixLabors.Fonts.Font font,
        string text,
        SixLabors.ImageSharp.Color color,
        float padding)
        {
            SixLabors.ImageSharp.Size imgSize = processingContext.GetCurrentSize();

            float targetWidth = imgSize.Width - (padding * 2);
            float targetHeight = imgSize.Height - (padding * 2);

            // measure the text size
            SixLabors.Fonts.FontRectangle size = TextMeasurer.Measure(text, new TextOptions(font));

            //find out how much we need to scale the text to fill the space (up or down)
            float scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height);

            //create a new font
            SixLabors.Fonts.Font scaledFont = new SixLabors.Fonts.Font(font, scalingFactor * font.Size);

            var center = new SixLabors.ImageSharp.PointF(imgSize.Width / 2, imgSize.Height / 2);

            var textGraphicsOptions = new TextOptions(font)
            {
                HorizontalAlignment = SixLabors.Fonts.HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };
            //return processingContext.DrawText(textGraphicsOptions, text, scaledFont, color, center);
            return processingContext.DrawText(text, scaledFont, color, center);
        }

        private static IImageProcessingContext ApplyScalingWaterMarkWordWrap(
            this IImageProcessingContext processingContext,
            SixLabors.Fonts.Font font,
            string text,
            SixLabors.ImageSharp.Color color,
            float padding)
        {
            SixLabors.ImageSharp.Size imgSize = processingContext.GetCurrentSize();
            float targetWidth = imgSize.Width - (padding * 2);
            float targetHeight = imgSize.Height - (padding * 2);

            float targetMinHeight = imgSize.Height - (padding * 3); // must be with in a margin width of the target height

            // now we are working i 2 dimensions at once and can't just scale because it will cause the text to
            // reflow we need to just try multiple times

            var scaledFont = font;
            FontRectangle s = new FontRectangle(0, 0, float.MaxValue, float.MaxValue);

            float scaleFactor = (scaledFont.Size / 2);// everytime we change direction we half this size
            int trapCount = (int)scaledFont.Size * 2;
            if (trapCount < 10)
            {
                trapCount = 10;
            }

            bool isTooSmall = false;

            while ((s.Height > targetHeight || s.Height < targetMinHeight) && trapCount > 0)
            {
                if (s.Height > targetHeight)
                {
                    if (isTooSmall)
                    {
                        scaleFactor = scaleFactor / 2;
                    }

                    scaledFont = new SixLabors.Fonts.Font(scaledFont, scaledFont.Size - scaleFactor);
                    isTooSmall = false;
                }

                if (s.Height < targetMinHeight)
                {
                    if (!isTooSmall)
                    {
                        scaleFactor = scaleFactor / 2;
                    }
                    scaledFont = new SixLabors.Fonts.Font(scaledFont, scaledFont.Size + scaleFactor);
                    isTooSmall = true;
                }
                trapCount--;

                s = TextMeasurer.Measure(text, new TextOptions(scaledFont)
                {
                   WrappingLength = targetWidth
                });
            }

            var center = new SixLabors.ImageSharp.PointF(padding, imgSize.Height / 2);
            var textGraphicsOptions = new TextOptions(font)
            {
                HorizontalAlignment = SixLabors.Fonts.HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Center,
                WrappingLength = targetWidth
            };
            //return processingContext.DrawText(textGraphicsOptions, text, scaledFont, color, center);
            return processingContext.DrawText( text, scaledFont, color, center);
        }
    }
}
